/*
 * 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。
 * 
 * 指定登记&发行网站： https://www.zhiqim.com/ 欢迎加盟知启蒙，[编程有你，知启蒙一路随行]。
 *
 * 本文采用《知启蒙许可证》，除非符合许可证，否则不可使用该文件！
 * 1、您可以免费使用、修改、合并、出版发行和分发，再授权软件、软件副本及衍生软件；
 * 2、您用于商业用途时，必须在原作者指定的登记网站，按原作者要求进行登记；
 * 3、您在使用、修改、合并、出版发行和分发时，必须包含版权声明、许可声明，及保留原作者的著作权、商标和专利等知识产权；
 * 4、您在互联网、移动互联网等大众网络下发行和分发再授权软件、软件副本及衍生软件时，必须在原作者指定的发行网站进行发行和分发；
 * 5、您可以在以下链接获取一个完整的许可证副本。
 * 
 * 许可证链接：http://zhiqim.org/licenses/zhiqim_register_publish_license.htm
 * 
 * 除非法律需要或书面同意，软件由原始码方式提供，无任何明示或暗示的保证和条件。详见完整许可证的权限和限制。
 */
package org.zhiqim.lottery;

import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Random;

import org.zhiqim.httpd.HttpRequest;
import org.zhiqim.httpd.context.ZmlContexts;
import org.zhiqim.kernel.annotation.AnAlias;
import org.zhiqim.kernel.extend.HashMapSO;
import org.zhiqim.kernel.extend.MapSO;
import org.zhiqim.kernel.json.Jsons;
import org.zhiqim.kernel.paging.PageResult;
import org.zhiqim.kernel.util.Arrays;
import org.zhiqim.lottery.dbo.LotteryInfo;
import org.zhiqim.lottery.dbo.LotteryUser;
import org.zhiqim.orm.ORM;
import org.zhiqim.orm.dbo.Selector;
import org.zhiqim.orm.dbo.Updater;

/**
 * 中奖展示器
 *
 * @version v1.4.1 @author zouzhigang 2021-4-18 新建与整理
 */
@AnAlias("LotteryPresenter")
public class LotteryPresenter
{
    private static HashMap<Long, List<LotteryUser>> ucache = new HashMap<>();
    private static HashMap<Long, Random> rcache = new HashMap<>();
    private static HashMap<Long, LotteryInfo> lcache = new HashMap<>();
    
    /** 查询中奖结束 */
    public static String doQueryCompleted(HttpRequest request) throws Exception
    {
        long lotteryId = request.getContextAttribute(LotteryBootstrap.class).getActiveLottery();
        if (lotteryId == 0)
        {
            return ZmlContexts.parseZmlPath(request, "/zview/zhiqim_lottery/presenter/error.zml", "error", "未传入抽奖编号");
        }
        
        LotteryInfo lottery = ORM.table().item(LotteryInfo.class, lotteryId);
        if (lottery == null)
        {
            return ZmlContexts.parseZmlPath(request, "/zview/zhiqim_lottery/presenter/error.zml", "error", "未传入抽奖编号");
        }
        
        Selector selector = new Selector();
        selector.addMust("lotteryId", lotteryId);
        selector.addMustThenG("userLuck", 0);
        selector.addOrderbyAsc("userLuck");
        
        List<LotteryUser> list = ORM.table().list(LotteryUser.class, selector);
        
        MapSO variableMap = new HashMapSO();
        variableMap.put("lottery", lottery);
        variableMap.put("list", list);
        
        return ZmlContexts.parseZmlPath(request, "/zview/zhiqim_lottery/presenter/completed.zml", variableMap);
    }
    
    public static String doQueryActive(HttpRequest request) throws Exception
    {
        long lotteryId = request.getContextAttribute(LotteryBootstrap.class).getActiveLottery();
        if (lotteryId == 0)
        {
            return ZmlContexts.parseZmlPath(request, "/zview/zhiqim_lottery/presenter/error.zml", "error", "未传入抽奖编号");
        }
        
        LotteryInfo lottery = ORM.table().item(LotteryInfo.class, lotteryId);
        if (lottery == null)
        {
            return ZmlContexts.parseZmlPath(request, "/zview/zhiqim_lottery/presenter/error.zml", "error", "未传入抽奖编号");
        }
        
        //2.3.加载未中奖的用户表，选出列表数，最多选5倍
        Selector selector = new Selector();
        selector.addMust("lotteryId", lotteryId);
        selector.addMust("userLuck", 0);
        
        int pageSize = lottery.getLotteryLine() * lottery.getLotteryRow();
        PageResult<LotteryUser> result = ORM.table().page(LotteryUser.class, 1, pageSize * 5, selector);
        
        //3.选出列表
        int size = result.size();
        Random random = new SecureRandom();
        List<LotteryUser> list = new ArrayList<>();
        for (int i=0;i<pageSize;i++)
        {
            int index = random.nextInt(size);
            list.add(result.list().get(index));
        }
        
        MapSO variableMap = new HashMapSO();
        variableMap.put("lottery", lottery);
        variableMap.put("list", list);
        
        return ZmlContexts.parseZmlPath(request, "/zview/zhiqim_lottery/presenter/active.zml", variableMap);
    }

    /** 开始 */
    public static void doStart(HttpRequest request) throws Exception
    {
        long lotteryId = request.getContextAttribute(LotteryBootstrap.class).getActiveLottery();
        if (lotteryId == 0)
        {
            request.setResponseError("未传入抽奖编号");
            return;
        }
        
        LotteryInfo lottery = ORM.table().item(LotteryInfo.class, lotteryId);
        if (lottery == null)
        {
            request.setResponseError("传入抽奖不存在或已停用");
            return;
        }
        
        List<LotteryUser> list = ORM.table().list(LotteryUser.class);
        ucache.put(lotteryId, list);
        rcache.put(lotteryId, new SecureRandom());
        lcache.put(lotteryId, lottery);
    }
    
    /** 停止 */
    public void doStop(HttpRequest request) throws Exception
    {
        long lotteryId = request.getContextAttribute(LotteryBootstrap.class).getActiveLottery();
        if (lotteryId == 0)
        {
            request.setResponseError("未传入抽奖编号");
            return;
        }
        
        LotteryInfo lottery = lcache.remove(lotteryId);
        Random random = rcache.remove(lotteryId);
        List<LotteryUser> ulist = ucache.remove(lotteryId);
        
        int pageSize = lottery.getLotteryLine() * lottery.getLotteryRow();
        
        //得到最后的列表
        List<LotteryUser> list = doList(random, pageSize, ulist);
        
        //得到中奖
        int num = lottery.getLotteryLuckPreNum();
        List<Integer> ilist = new ArrayList<>();
        List<Long> luckList = new ArrayList<>();
        for (int i=0;i<num;i++)
        {
            int index = random.nextInt(pageSize);
            luckList.add(list.get(index).getUserId());
            ilist.add(index);
        }
        
        List<LotteryUser> superList = ORM.table().list(LotteryUser.class, new Selector("lotteryId", lotteryId).addMust("userType", 2));
        if (!superList.isEmpty())
        {//判断专席，进行替换
            for (int i=0;i<superList.size();i++)
            {
                LotteryUser sUser = superList.get(i);
                luckList.set(i, sUser.getUserId());
                int ind = ilist.get(i);
                list.set(ind, sUser);
            }
        }
        
        long[] userIds = Arrays.toArrayLong(luckList);
        Updater updater = new Updater();
        updater.addMustInLong("userId", userIds);
        updater.addField("userLuck", 1);
        
        ORM.table().update(LotteryUser.class, updater);
        
        //组装数据
        List<String> slist = new ArrayList<>();
        for (LotteryUser user : list)
        {
            slist.add(user.getUserName());
        }
        
        int count = ORM.table().count(LotteryUser.class, new Selector("lotteryId", lotteryId).addMustThenG("userLuck", 0));
        if (count >= lottery.getLotteryLuckNum())
        {//结束
            ORM.table().update(LotteryInfo.class, new Updater().addMust("lotteryId", lotteryId).addField("lotteryStatus", 12));
        }
        
        HashMapSO result = new HashMapSO();
        result.put("allList", slist);
        result.put("luckList", ilist);
        result.put("completed", count >= lottery.getLotteryLuckNum());
        
        //返回列表
        request.setResponseResult(Jsons.toString(result));
    }
    
    /** 显示 */
    public void doShow(HttpRequest request) throws Exception
    {
        long lotteryId = request.getContextAttribute(LotteryBootstrap.class).getActiveLottery();
        if (lotteryId == 0)
        {
            request.setResponseError("未传入抽奖编号");
            return;
        }
        
        List<LotteryUser> ulist = ucache.get(lotteryId);
        if (ulist == null)
        {
            request.setResponseError("传入的抽奖已停止");
            return;
        }
        
        Random random = rcache.get(lotteryId);
        LotteryInfo lottery = lcache.get(lotteryId);
        
        int pageSize = lottery.getLotteryLine() * lottery.getLotteryRow();
        List<LotteryUser> list = doList(random, pageSize, ulist);
        
        //组装数据
        List<String> slist = new ArrayList<>();
        for (LotteryUser user : list)
        {
            slist.add(user.getUserName());
        }
        
        //返回列表
        request.setResponseResult(Jsons.toString(slist));
    }
    
    private List<LotteryUser> doList(Random random, int pageSize, List<LotteryUser> uList)
    {
        int size = uList.size();
        List<LotteryUser> list = new ArrayList<>();
        
        if (size >= pageSize)
        {//足够的情况下不重复
            for (int i=0;i<pageSize;)
            {
                int index = random.nextInt(size);
                LotteryUser user = uList.get(index);
                if (list.contains(user))
                    continue;
                
                list.add(user);
                i++;
            }
        }
        else
        {
            for (int i=0;i<pageSize;i++)
            {
                int index = random.nextInt(size);
                list.add(uList.get(index));
            }
        }
        
        return list;
    }
}
